package com.tarena.lbs.attach.service.impl;

;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.EncodeHintType;
import com.google.zxing.MultiFormatWriter;
import com.google.zxing.WriterException;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
import com.tarena.lbs.attach.dao.mapper.AttachMapper;
import com.tarena.lbs.attach.dao.repository.AttachRepository;
import com.tarena.lbs.attach.enums.AttachResultEnum;
import com.tarena.lbs.attach.enums.FileTypeEnum;
import com.tarena.lbs.attach.pojo.dto.AttachDTO;
import com.tarena.lbs.attach.pojo.dto.AttachQrDTO;
import com.tarena.lbs.attach.pojo.param.AttachParam;
import com.tarena.lbs.attach.pojo.param.AttachQRParam;
import com.tarena.lbs.attach.pojo.param.PicUpdateParam;
import com.tarena.lbs.attach.pojo.po.AttachPO;
import com.tarena.lbs.attach.pojo.query.AttachQuery;
import com.tarena.lbs.attach.pojo.vo.FileVO;
import com.tarena.lbs.attach.service.AttachService;
import com.tarena.lbs.base.protocol.exception.BusinessException;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.*;

@Service
@Slf4j
public class AttachServiceImpl implements AttachService {

    @Resource
    private AttachRepository attachRepository;
    @Value("${static.resource.path:D:/files/}")
    private String staticResourcePath;

    @Value("${qr_code_url:http://localhost:8080/qrcode/}")
    private String qrCodeUrl;

    /**
     * 插入附件信息
     *
     * @param file 文件对象，用于获取文件的元数据
     * @param fileUuid 文件的唯一标识符
     * @return 返回一个包含附件信息的DTO对象
     */
    @Override
    public AttachDTO insertAttachInfo(MultipartFile file, String fileUuid) {
        // 创建一个新的附件POJO对象
        AttachPO attach = new AttachPO();
        // 设置文件的唯一标识符
        attach.setFileUuid(fileUuid);
        // 设置文件的原始名称
        attach.setClientFileName(file.getOriginalFilename());
        // 设置文件的大小
        attach.setContentLength(file.getSize());
        // 设置文件的内容类型
        attach.setContentType(file.getContentType());
        // 初始化下载次数为0
        attach.setDownloadTimes(0);
        // 设置业务类型，默认为0
        attach.setBusinessType(0);
        // 设置业务ID，默认为0
        attach.setBusinessId(0);
        // 设置状态，默认为0
        attach.setStatus(0);
        // 设置创建用户的ID，默认为0
        attach.setCreateUserId(0L);
        // 设置创建时间戳
        attach.setGmtCreate(System.currentTimeMillis());
        // 设置修改用户的ID，默认为0
        attach.setModifiedUserId(0L);
        // 设置修改时间戳
        attach.setGmtModified(System.currentTimeMillis());
        // 设置备注信息，默认为空字符串
        attach.setRemark("");
        // 设置是否为封面，默认为0
        attach.setIsCover(0);
        // 设置宽度，默认为0
        attach.setWidth(0);
        // 设置高度，默认为0
        attach.setHeight(0);
        // 设置创建用户的名称，默认为空字符串
        attach.setCreateUserName("");
        // 设置修改用户的名称，默认为空字符串
        attach.setModifiedUserName("");
        // 记录日志，调试级别，打印保存附件信息
        log.debug("保存附件信息：{}", attach);
        // 调用Mapper方法插入附件信息
        attachRepository.insertAttach(attach);

        // 创建一个新的附件DTO对象
        AttachDTO dto = new AttachDTO();
        // 设置DTO对象的ID
        dto.setId(attach.getId());
        // 设置DTO对象的文件唯一标识符
        dto.setFileUuid(fileUuid);
        // url由Controller补充
        return dto;
    }

    /**
     * 获取附件信息列表
     *
     * @param attachQuery 附件查询参数对象
     * @return 返回一个包含附件信息DTO对象的列表
     */
    @Override
    public List<AttachDTO> getAttachInfo(AttachQuery attachQuery) {
        // 调用Mapper方法根据查询参数获取附件信息列表
        List<AttachPO> attachList = attachRepository.selectAttachByQuery(attachQuery);
        // 创建一个新的附件DTO对象列表
        List<AttachDTO> dtoList = new ArrayList<>();
        // 遍历附件信息列表
        for (AttachPO attach : attachList) {
            // 创建一个新的附件DTO对象
            AttachDTO dto = new AttachDTO();
            // 将附件POJO对象的属性复制到DTO对象
            BeanUtils.copyProperties(attach, dto);
            // 将DTO对象添加到列表中
            dtoList.add(dto);
        }
        // 返回附件DTO对象列表
        return dtoList;
    }

    /**
     * 批量更新附件的业务信息
     *
     * @param picParams 包含多个图片更新参数的列表
     * @return 返回更新操作是否成功
     */
    @Override
    public boolean batchUpdateBusiness(List<PicUpdateParam> picParams) {
        // 调用Mapper方法批量更新附件的业务信息
        int rows = attachRepository.batchUpdateAttachByIdOrFileUUID(picParams);
        // 返回更新操作是否成功的布尔值
        return rows > 0;
    }

    /**
     * 生成二维码
     *
     * @param attachQRParam 附件二维码参数对象，包含二维码的内容
     * @return 返回一个包含二维码信息的DTO对象
     */
    @Override
    public AttachQrDTO generateQrCode(AttachQRParam attachQRParam) {
        // 获取二维码的内容
        String content = attachQRParam.getContent();
        // 生成一个唯一的文件名标识符
        String uuid = UUID.randomUUID().toString().replace("-", "");
        // 拼接文件名和扩展名
        String fileName = uuid + ".png";
        // 拼接文件的完整路径
        String filePath = staticResourcePath + fileName;
        try {
            // 调用私有方法生成二维码图片
            BufferedImage image = createQrImage(content, 300, 300);
            // 创建一个文件对象
            File file = new File(filePath);
            // 如果文件的父目录不存在，则创建父目录
            if (!file.getParentFile().exists()) {
                file.getParentFile().mkdirs();
            }
            // 将二维码图片写入文件
            ImageIO.write(image, "png", file);
            // 创建一个新的二维码DTO对象
            AttachQrDTO qrDTO = new AttachQrDTO();
            // 设置二维码DTO对象的文件唯一标识符
            qrDTO.setFileUuid(uuid);
            // 设置二维码DTO对象的URL
            qrDTO.setUrl(qrCodeUrl + fileName);
            // 返回二维码DTO对象
            return qrDTO;
        } catch (Exception e) {
            // 如果生成二维码失败，则抛出运行时异常
            throw new RuntimeException("生成二维码失败", e);
        }
    }


    /**
     * 使用ZXing生成二维码图片
     *
     * @param content 二维码的内容
     * @param width 二维码的宽度
     * @param height 二维码的高度
     * @return 返回生成的二维码图片
     */
    private BufferedImage createQrImage(String content, int width, int height) throws WriterException {
        // 创建一个包含编码提示的Map对象
        Map<EncodeHintType, Object> hints = new HashMap<>();
        // 设置字符集为UTF-8
        hints.put(EncodeHintType.CHARACTER_SET, "UTF-8");
        // 设置错误纠正级别为M
        hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.M);
        // 设置边距为1
        hints.put(EncodeHintType.MARGIN, 1);
        // 使用MultiFormatWriter生成二维码的BitMatrix对象
        BitMatrix bitMatrix = new MultiFormatWriter().encode(content, BarcodeFormat.QR_CODE, width, height, hints);
        // 创建一个新的BufferedImage对象
        BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
        // 遍历BitMatrix，设置图片的像素值
        for (int x = 0; x < width; x++) {
            for (int y = 0; y < height; y++) {
                image.setRGB(x, y, bitMatrix.get(x, y) ? 0xFF000000 : 0xFFFFFFFF);
            }
        }
        // 返回生成的二维码图片
        return image;
    }

}